#include "general/Heap.h"
#include <stdio.h>
#include <memory>
#include <functional>

template<>
struct std::greater<std::shared_ptr<int>>{
    bool operator()(const std::shared_ptr<int>&lhs, const std::shared_ptr<int>&rhs)const{
        if(lhs == nullptr)
            return false;
        else if(rhs == nullptr)
            return true;

        return *lhs > *rhs;
    }
};

int main(int argc, char const *argv[]) {
    for(int i = 0; i < 7; ++i){
        int nLeftIndex = LeftIndex(i);
        int nRightIndex = RightIndex(i);
        int nParentIndex = ParentIndex(i);

        printf("Index: %d, Left: %d, Right: %d, Parent: %d\n", i, nLeftIndex, nRightIndex, nParentIndex);
    }


    int nElements[] = {5, 3, 17, 10, 84, 19, 6, 22, 9 };
    BuildHeap(nElements, sizeof(nElements) / sizeof(int) - 1);

    for(auto elem : nElements){
        printf("%d, ", elem);
    }
    
    // printf("]]\n");
    // UpgradeHeapElement(nElements, 8, 100);
    // for(auto elem : nElements){
    //     printf("%d, ", elem);
    // }
    printf("\n-------------------\n");

    int nElements1[] = {5, 3, 17, 10, 84, 19, 6, 22, 9 };
    Heap<int> heap(sizeof(nElements) / sizeof(int));

    for(auto e : nElements1){
        heap.Insert(e);
    }

    int* pTest;
    while((pTest = heap.PopFirst())){
        printf("%d,", *pTest);
    }
    printf("\n---------------------\n");

    Heap<std::shared_ptr<int>, std::greater<std::shared_ptr<int>>> heap1(sizeof(nElements) / sizeof(int));
    for(auto e : nElements1){
        heap1.Insert(std::make_shared<int>(e));
    }

    std::shared_ptr<int>* pVal;
    while((pVal = heap1.PopFirst())){
        std::shared_ptr<int> ptrVal = *pVal; 
        printf("%d, ", *ptrVal);
    }

    printf("\n");
    printf("****************************\n");

    HeapSort(nElements1, sizeof(nElements1) / sizeof(int) - 1);

    for(auto elem : nElements1){
        printf("%d, ", elem);
    }
    printf("\n");

    std::pair<int*, int> ItemEntry;
    int nLen = sizeof(nElements) / sizeof(int) - 1;
    while((ItemEntry = PopHeapFirst(nElements, nLen)).first != nullptr){
        nLen = ItemEntry.second;
        printf("%d, %d\n", *ItemEntry.first, ItemEntry.second);
    }

    for(auto elem : nElements1){
        auto resultEntry = InsertHeapElement(nElements, elem, nLen);
        if(resultEntry.first){
            nLen = resultEntry.second;
            for(int i = 0; i <= nLen; ++i)
                printf("result:%d, value:%d\n", nLen, nElements[i]);
            printf("\n");
        }
    }
    
    BuildHeap<int, std::less<int>>(nElements1, sizeof(nElements1) / sizeof(int) - 1);

    UpgradeHeapElement<int, std::less<int>>(nElements1, 8, 1);
    for(auto elem : nElements1){
        printf("%d, ", elem);
    }
    printf("\n");


    nLen = DeleteHeapElement(nElements, 0, 8);
    for(int i = 0; i <= nLen; ++i){
        printf("%d, ", nElements[i]);
    }
    printf("\n");

    
    return 0;
}